﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Storage;
using Microsoft.Xna.Framework.Content.Pipeline.Serialization.Compiler;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;

using ComponentItem = System.Collections.Generic.KeyValuePair<string, BlackStar.Component>;

namespace BlackStar
{
    public delegate void ComponentEvent(Component sender);
    public delegate void ComponentMouseEvent(Component sender, MouseEventArgs e);
    public delegate void ComponentKeyEvent(Component sender, KeyEventArgs e);

    public class GUI : DrawableGameComponent
    {
        public event MouseEvent MouseUp;
        public event MouseEvent MouseDown;
        public event MouseEvent MouseClick;
        public event MouseEvent MouseDoubleClick;
        public event MouseEvent MouseScroll;
        public event KeyEvent KeyDown;
        public event KeyEvent KeyUp;
        public event ComponentEvent ComponentCreated;

        Screen rootComponent = new Screen();

        internal Theme theme;
        internal SpriteBatch batch;
        public Mouse mouse;
        public Keyboard keyboard;
        public Clipboard clipboard = new Clipboard();

        public int ClickSpeed = 1000;

        string myContentName;
        string myThemeName;
        string myKeymap;

        protected Component myHasFocus;

        public Component HasFocus
        {
            get { return myHasFocus; }
            set
            {
                if (myHasFocus != null)
                {
                    if (myHasFocus != value)
                    {
                        myHasFocus.DoLeave();
                        myHasFocus = value;
                        myHasFocus.DoEnter();
                    }
                }
                else
                {
                    myHasFocus = value;
                    myHasFocus.DoEnter();
                }
            }
        }

        public GUI(Game g, string contentName, string themeName, string keyMap)
            : base(g)
        {

            Game.Components.Add(this);

            myKeymap = keyMap;
            myContentName = contentName;
            myThemeName = themeName;

            // always draw the GUI elements last.
            this.DrawOrder = int.MaxValue;
        }

        protected override void LoadContent()
        {
            mouse = new Mouse(this);
            mouse.MouseClick += new MouseEvent(DoMouseClick);
            mouse.MouseDoubleClick += new MouseEvent(DoMouseDoubleClick);
            mouse.MouseDown += new MouseEvent(DoMouseDown);
            mouse.MouseUp += new MouseEvent(DoMouseUp);
            mouse.MouseMove += new MouseEvent(DoMouseMove);
            mouse.MouseScroll += new MouseEvent(mouse_MouseScroll);

            batch = new SpriteBatch(Game.GraphicsDevice);

            keyboard = new Keyboard(this.Game.Content, myKeymap);
            keyboard.KeyDown += new KeyEvent(DoKeyDown);

            // theme must be loaded before the components.
            theme = Game.Content.Load<Theme>(myThemeName);
            theme.GUI = this;
            theme.LoadContent();

            // these commands on the root component will recurse.
            rootComponent.LoadComponents(Game.Content, myContentName);
            rootComponent.gui = this;
            rootComponent.ResumeLayout();
            rootComponent.OnCreate();

        }

        void mouse_MouseScroll(MouseEventArgs e)
        {
            Component Target = rootComponent.FindComponent(e.Location);
            if (Target != null)
            { Target.DoMouseScroll(e); }
            else
            { OnMouseScroll(e); }
        }

        public override void Draw(GameTime gameTime)
        {
            batch.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.Deferred, SaveStateMode.SaveState);

            rootComponent.Draw();
            mouse.Draw();

            batch.End();
        }

        public override void Update(GameTime gameTime)
        {
            mouse.Update(gameTime);
            keyboard.Update(gameTime);
            theme.Update(gameTime);
            rootComponent.Update(gameTime);
        }

        protected internal void OnComponentCreated(Component c)
        {
            if (this.ComponentCreated != null) ComponentCreated(c);
        }

        public void DrawRectangle(Rectangle rect, Color color, bool fill)
        {
            if (fill)
            { batch.Draw(theme.pixel, rect, color); }
            else
            {
                
            }
        }

        private void DoKeyDown(KeyEventArgs e)
        { if (HasFocus != null) { HasFocus.DoKeyDown(e); } else { OnKeyDown(e); } }

        private void DoKeyUp(KeyEventArgs e)
        { if (HasFocus != null) { HasFocus.DoKeyUp(e); } else { OnKeyUp(e); } }

        private void DoMouseClick(MouseEventArgs e)
        {
            Component Target = rootComponent.FindComponent(e.Location);
            if (Target != null)
            { Target.DoMouseClick(e); }
            else
            { OnMouseClick(e); }
        }

        private void DoMouseDoubleClick(MouseEventArgs e)
        {
            Component Target = rootComponent.FindComponent(e.Location);
            if (Target != null)
            { Target.DoMouseDoubleClick(e); }
            else
            { OnMouseDoubleClick(e); }
        }

        private void DoMouseDown(MouseEventArgs e)
        {
            Component Target = rootComponent.FindComponent(e.Location);
            if (Target != null)
            { Target.DoMouseDown(e); }
            else
            { myHasFocus = null; OnMouseDown(e); }
        }

        private void DoMouseUp(MouseEventArgs e)
        {
            Component Target = rootComponent.FindComponent(e.Location);
            if (Target != null)
            { Target.DoMouseUp(e); }
            else
            { OnMouseUp(e); };
        }

        private void DoMouseMove(MouseEventArgs e)
        {
            Component Target = rootComponent.FindComponent(e.Location);
            if (Target != null)
            { Target.DoMouseMove(e); }
        }

        private void OnKeyDown(KeyEventArgs e) { if (KeyDown != null)KeyDown(e); }
        private void OnKeyUp(KeyEventArgs e) { if (KeyUp != null)KeyUp(e); }
        private void OnMouseUp(MouseEventArgs e) { if (MouseUp != null) MouseUp(e); }
        private void OnMouseDown(MouseEventArgs e) { if (MouseDown != null) MouseDown(e); }
        private void OnMouseClick(MouseEventArgs e) { if (MouseClick != null) MouseClick(e); }
        private void OnMouseDoubleClick(MouseEventArgs e) { if (MouseDoubleClick != null) MouseDoubleClick(e); }
        private void OnMouseScroll(MouseEventArgs e) { if (MouseScroll != null) MouseScroll(e); }

        public Component FindComponent(string name)
        { return rootComponent.FindComponent(name); }

        public Component FindComponent(Point Location)
        { return rootComponent.FindComponent(Location); }

    }
}
